package com.cruel_wandering.wifi_geo_predictor.location;

import java.util.LinkedList;

import com.cruel_wandering.wifi_geo_predictor.CellID;
import com.cruel_wandering.wifi_geo_predictor.Logger;
import com.cruel_wandering.wifi_geo_predictor.util.MyTimer;

import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;

public class MyCellIDProvider implements MyLocationProvider {
	private static final String TAG = "MyCellProvider";
	private static final long MIN_DELAY = 30000;// 30 seconds
	private boolean enabled = true;
	private Location lastLocation;
	private MyTimer timer;
	private Context ctx;
	private LinkedList<LocationListener> listeners;
	private long delay;
	private boolean pollingStopped;
	
	public MyCellIDProvider(Context sourceCtx){
		ctx = sourceCtx;
		timer = new MyTimer(sourceCtx);
		pollingStopped = true;
		listeners = new LinkedList<LocationListener>();
	}

	final private Runnable getLocation = new Runnable() {
		public void run()
		{
			log("Creating CellID");
			CellID cid = new CellID(ctx);
			log("Getting new location");
			Location loc = cid.getLocation();
			log("New location is " + loc);

			lastLocation = new Location(loc);

			for (LocationListener l : listeners)
				l.onLocationChanged(lastLocation);
			}
		};

	private void startPolling()
	{
		if (!pollingStopped)
			return;

		pollingStopped = false;
		/* XXX: Assuming that Oracle recalculates the delay after every
		 * location update, and reregisters the listener, it is ok to execute
		 * getLocation just once. 
		 */
		timer.schedule(getLocation, delay);
	}

	private void stopPolling()
	{
		pollingStopped = true;
		timer.cancel(getLocation);
	}

	public Location getLastKnownLocation() {
		return lastLocation;
	}

	public boolean isEnabled() {
		return enabled;
	}

	public boolean meetsCriteria(Criteria criteria) {
		if(criteria.isAltitudeRequired()) return false;
		if(criteria.isSpeedRequired())return false;
		if(criteria.getAccuracy() < Criteria.ACCURACY_COARSE)return false;
		if(!criteria.isCostAllowed())return false;
		return true;
	}

	public void removeUpdates(LocationListener listener) {
		if(listeners.remove(listener)) {
			Logger.getInstance(ctx).log(TAG, "listener was removed");
		}else{
			Logger.getInstance(ctx).log(TAG, "listener was not removed");
		}

		if (listeners.isEmpty())
			stopPolling();
	}

	public void requestLocationUpdates(long minTime, float minDistance,
			LocationListener listener) {
		listeners.addLast(listener);
		if(minTime < MIN_DELAY)
			minTime = MIN_DELAY;

		delay = minTime;
		startPolling();
	}

	public void setEnabled(boolean enabled)
  {
		this.enabled = enabled;

		if (enabled)
			startPolling();
		else
			stopPolling();
  }

	public void log(String msg)
	{
		Logger.logAndToast(ctx, this.getClass().getName(), msg);
	}
}
